package golf.stockdata.batch;

import golf.stockdata.connector.tfex.TFEXConnector;
import golf.stockdata.connector.tfex.dataobject.set50.AllContractsTradingInfo_Type;
import golf.stockdata.connector.tfex.dataobject.set50.ContractTradingInfo_Type;
import golf.stockdata.framework.batch.Job;
import golf.stockdata.framework.exception.ApplicationException;
import golf.stockdata.framework.hbmdao.Tfex;
import golf.stockdata.framework.hbmdao.TfexDailyPrice;
import golf.stockdata.framework.hbmdao.TfexDailyPriceId;
import golf.stockdata.framework.hbmdao.TfexId;
import golf.stockdata.framework.util.hbm.HibernateUtil;
import golf.stockdata.framework.util.hbm.IdGenerator;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;

public class TFEXDataCollectorJob implements Job{
	
	private static Logger logger = Logger.getLogger(TFEXDataCollectorJob.class);
	
	HashMap<String, String> batchProps = null;
	private TFEXConnector tfexConnector;
	
	private Session session;
	
	private boolean isInitialized = false;
	
	public TFEXDataCollectorJob(TFEXConnector _tfexConnector){
		tfexConnector = _tfexConnector;
	}

	public void initializeJob(HashMap<String, String> prop) {
		logger.debug(">>> initializeJob");
		batchProps = prop;
		
		session = HibernateUtil.createHibernatesession();
		
//		isInitialized = true;
		
		logger.debug("<<< initializeJob");
	}

	public void execute() {
		
		logger.debug(">>> execute");
		
		try {
			
			logger.debug("Begin transaction");
			session.getTransaction().begin();
			
			logger.debug("Getting all TFEX Info");
			AllContractsTradingInfo_Type allData = (AllContractsTradingInfo_Type) tfexConnector.call();
			
			//Sub-query for Max timestamp thru DetachedCriteria
			DetachedCriteria maxTs = DetachedCriteria.forClass(TfexDailyPrice.class, "sub")
					.setProjection(Projections.max("id.tfxdpHostTs") )
					.add(Restrictions.eqProperty("sub.id.tfexId","main.id.tfexId"));
			DetachedCriteria maxTsTFEX = DetachedCriteria.forClass(Tfex.class, "sub")
					.setProjection(Projections.max("id.tfexHostTs"))
					.add(Restrictions.eqProperty("sub.id.tfexId","main.id.tfexId"));
			
			for(ContractTradingInfo_Type tfexData:allData.getContractList()){
				
				if(!tfexData.getHigh().equals("-")){
					
					logger.debug("seems to have proper data, not just -");
					
					Tfex tfex = (Tfex)session.createCriteria(Tfex.class, "main")
							.add(Property.forName("id.tfexHostTs").eq(maxTsTFEX) )
							.add(Property.forName("tfexSymbol").eq(tfexData.getSymbol()) )
							.uniqueResult();
					
					TfexDailyPrice dailyPrice = null;
					
					if(tfex != null){
						
						logger.debug("TFEX Data for " + tfexData.getSymbol() + " exists in the DB");
						
						dailyPrice = (TfexDailyPrice)session.createCriteria(TfexDailyPrice.class, "main")
								.add(Property.forName("id.tfxdpHostTs").eq(maxTs) )
								.add(Property.forName("id.tfexId").eq(tfex.getId().getTfexId()) )
								.uniqueResult();
					}else{
						
						logger.debug("TFEX Data for " + tfexData.getSymbol() + " does not exist in the DB, create a new row");
						
						int tfxtpId = 0;
						if(tfexData.getSymbol().indexOf("USD") == 0){
							logger.debug("type is USD");
							tfxtpId = 2;
						}else if(tfexData.getSymbol().indexOf("S50") == 0){
							logger.debug("type is SET50");
							tfxtpId = 1;
						}
						
						tfex = new Tfex(new TfexId(IdGenerator.getNext(), new Timestamp(System.currentTimeMillis())), 
								tfxtpId, tfexData.getSymbol(), tfexData.getContractMonth(), "C");
						
						logger.debug("persisting this new TFEX contract");
						
						session.save(tfex);
					}
					
					if(dailyPrice == null
							|| dailyPrice.getTfxdpVolume() != Integer.valueOf(tfexData.getVol().replaceAll(",", ""))
							|| dailyPrice.getId().getTfxdpHostTs().getTime() - System.currentTimeMillis() < -300000){
						
						logger.debug("Creating a new daily price row");
						
						dailyPrice = new TfexDailyPrice(
								new TfexDailyPriceId(tfex.getId().getTfexId(), new Timestamp(System.currentTimeMillis())), 
								new BigDecimal(tfexData.getOpen().replaceAll(",", "")),
								new BigDecimal(tfexData.getHigh().replaceAll(",", "")), 
								new BigDecimal(tfexData.getLow().replaceAll(",", "")),//tfxdpLowPrice, 
								new BigDecimal(tfexData.getBid().replaceAll(",", "")),//tfxdpBidPrice, 
								new BigDecimal(tfexData.getOffer().replaceAll(",", "")),//tfxdpOfferPrice, 
								new BigDecimal(tfexData.getLast().replaceAll(",", "")),//tfxdpLastPrice, 
								new BigDecimal(tfexData.getChg().replaceAll(",", "")),//tfxdpPriceChange, 
								tfexData.getVol().equals("-") ? 0 : Long.valueOf(tfexData.getVol().replaceAll(",", "")),//tfxdpVolume, 
								tfexData.getoI().equals("-") ? 0 : Long.valueOf(tfexData.getoI().replaceAll(",", "")),//tfxdpOi, 
								tfexData.getPriorSP().equals("-") ? BigDecimal.ZERO : new BigDecimal(tfexData.getPriorSP().replaceAll(",", "")),//tfxdpPriorSp, 
								tfexData.getsP().equals("-") ? BigDecimal.ZERO : new BigDecimal(tfexData.getsP().replaceAll(",", "")),//tfxdpCurrentSp, 
								"C");
						
						logger.debug("persisting the daily price");
						
						session.save(dailyPrice);
					}
					
				}
				
			}
			
			logger.debug("committing");
			
			session.getTransaction().commit();
			session.close();
			
		} catch (ApplicationException e) {
			logger.error(e);
			if(logger.isDebugEnabled()){
				StringWriter stack = new StringWriter();
				e.printStackTrace(new PrintWriter(stack));
				logger.debug(stack.toString());
			}
		} finally {
			try{
				if(session.isOpen()){
					session.getTransaction().rollback();
				}
			}catch(Exception e){
				logger.warn(e);
				if(logger.isDebugEnabled()){
					StringWriter stack = new StringWriter();
					e.printStackTrace(new PrintWriter(stack));
					logger.debug(stack.toString());
				}
			}
		}
		
		logger.debug("<<< execute");

	}

	public boolean isIntialized() {
		return isInitialized;
	}

}
